package pingpongdojo.dialog;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.dialogs.TitleAreaDialog;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

public abstract class FormDialog extends TitleAreaDialog {

	protected static class FormItemKey {
		private String key;

		public FormItemKey(String key) {
			this.key = key;
		}

		public boolean equals(Object otherObject) {
			if (!(otherObject instanceof FormItemKey)) {
				return false;
			}

			FormItemKey otherKey = (FormItemKey) otherObject;
			return key.equals(otherKey.key);
		}

		public int hashCode() {
			return key.hashCode();
		}
	}

	protected static abstract class FormItem {
		protected FormItemKey key;
		protected String label;

		public FormItem(FormItemKey key, String label) {
			this.key = key;
			this.label = label;
		}

		public FormItemKey getKey() {
			return key;
		}

		public String getLabel() {
			return label;
		}

		public abstract void setValue(String value);

		public abstract String getValue();

		public abstract void initWidget(Composite parent);

		public abstract Control getControl();
	}

	protected static class TextFieldFormItem extends FormItem {
		protected Text textField;

		public TextFieldFormItem(FormItemKey key, String label) {
			super(key, label);
		}

		public void initWidget(Composite parent) {
			this.textField = new Text(parent, SWT.SINGLE | SWT.BORDER);
		}

		@Override
		public Control getControl() {
			return textField;
		}

		@Override
		public void setValue(String value) {
			textField.setText(value);
		}

		@Override
		public String getValue() {
			if (textField == null) {
				return null;
			}
			return textField.getText();
		}
	}

	protected static class ComboBoxFormItem extends FormItem {
		private List<String> options;
		private Combo comboBox;

		public ComboBoxFormItem(FormItemKey key, String label,
				List<String> options) {
			super(key, label);
			this.options = options;
		}

		@Override
		public void setValue(String value) {
			comboBox.select(options.indexOf(value));
		}

		@Override
		public String getValue() {
			if (comboBox == null) {
				return null;
			}
			return comboBox.getItem(comboBox.getSelectionIndex());
		}

		@Override
		public void initWidget(Composite parent) {
			this.comboBox = new Combo(parent, SWT.VERTICAL | SWT.DROP_DOWN
					| SWT.BORDER | SWT.READ_ONLY);

			comboBox.setItems(options.toArray(new String[options.size()]));
			comboBox.select(0);
		}

		@Override
		public Control getControl() {
			return comboBox;
		}
	}

	private final String title;
	private final String message;
	private Map<FormItemKey, FormItem> items = new LinkedHashMap<FormItemKey, FormItem>();

	public FormDialog(String title, String message, Shell parentShell) {
		super(parentShell);

		this.title = title;
		this.message = message;
	}

	protected void addFormItem(FormItem item) {
		items.put(item.getKey(), item);
	}

	protected FormItem getFormItem(FormItemKey key) {
		return items.get(key);
	}

	protected void removeFormItem(FormItemKey key) {
		items.remove(key);
	}

	protected void clearFormItems() {
		items.clear();
	}

	@Override
	public void create() {
		super.create();

		setTitle("PingPong Dojo: " + title);
		setMessage(message, IMessageProvider.INFORMATION);
	}

	protected abstract String getOKButtonTitle();

	@Override
	protected Control createDialogArea(Composite parent) {

		GridLayout layout = new GridLayout();
		layout.numColumns = 2;
		parent.setLayout(layout);

		for (FormItem item : items.values()) {
			Label label = new Label(parent, SWT.NONE);
			label.setText(item.getLabel());
			label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false));

			item.initWidget(parent);
			item.getControl().setLayoutData(
					new GridData(SWT.FILL, SWT.CENTER, true, false));
		}

		return parent;
	}

	@Override
	protected void createButtonsForButtonBar(Composite parent) {
		GridData gridData = new GridData();
		gridData.verticalAlignment = GridData.FILL;
		gridData.horizontalSpan = 3;
		gridData.grabExcessHorizontalSpace = true;
		gridData.grabExcessVerticalSpace = true;
		gridData.horizontalAlignment = SWT.CENTER;

		parent.setLayoutData(gridData);

		createOkButton(parent, OK, getOKButtonTitle(), true);

		Button cancelButton = createButton(parent, CANCEL, "Cancel", false);

		cancelButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				setReturnCode(CANCEL);
				close();
			}
		});
	}

	protected Button createOkButton(Composite parent, int id, String label,
			boolean defaultButton) {
		((GridLayout) parent.getLayout()).numColumns++;
		Button button = new Button(parent, SWT.PUSH);
		button.setText(label);
		button.setFont(JFaceResources.getDialogFont());
		button.setData(new Integer(id));
		button.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent event) {
				okPressed();
			}
		});
		if (defaultButton) {
			Shell shell = parent.getShell();
			if (shell != null) {
				shell.setDefaultButton(button);
			}
		}
		setButtonLayoutData(button);
		return button;
	}

	@Override
	protected boolean isResizable() {
		return false;
	}

	@Override
	protected void okPressed() {
		super.okPressed();
	}

}